package club.xyes.pi4j.i2c;

import com.pi4j.io.gpio.GpioPinDigitalOutput;

/**
 * 2018/11/8 Create by 郭文梁
 * GpioIICDevice
 * 通过GPIO模拟IIC协议
 *
 * @author 郭文梁
 * @date 2018/11/8
 */
public class GpioIICDevice {
    private static final int ONE_BYTE = 8;
    private static final int MAX_WIDTH = 128;
    private static final int MAX_LINE = 8;

    private static final char[] INIT_CMD_LIST = {
            0xAE,
            0x00,
            0x10,
            0x40,
            0xB0,
            0x81,
            0xFF,
            0xA1,
            0xA6,
            0xA8,
            0x3F,
            0xC8,
            0xD3,
            0x00,
            0xD5,
            0x80,
            0xD8,
            0x05,
            0xD9,
            0xF1,
            0xDA,
            0x12,
            0xDB,
            0x30,
            0x8D,
            0x14,
            0xAF

    };

    private final GpioPinDigitalOutput sda;
    private final GpioPinDigitalOutput scl;

    public GpioIICDevice(GpioPinDigitalOutput sda, GpioPinDigitalOutput scl) {
        this.sda = sda;
        this.scl = scl;
    }

    public void sdaDown() {
        sda.low();
    }

    public void sdaUp() {
        sda.high();
    }

    public void sclDown() {
        scl.low();
    }

    public void sclUp() {
        scl.high();
    }

    public void iicStart() {
        sclDown();
        sdaDown();
        sclUp();
        sdaUp();
    }

    public void iicStop() {
        sclUp();
//        sclDown();
        sdaDown();
        sdaUp();
    }

    public void waitAck() {
        sclUp();
        sclDown();
    }

    public void write(char data) {
        char i;
        char m, da;
        da = data;
        sclDown();
        for (i = 0; i < 8; i++) {
            m = da;
            m &= 0x80;
            if (m == 0x80) {
                sdaUp();
            } else {
                sdaDown();
            }
            da <<= 1;
            sclUp();
            sclDown();
        }
    }

    public void writeCommand(char data) {
        iicStart();
        write((char) 0x78);
        waitAck();
        write((char) 0x00);
        waitAck();
        write(data);
        waitAck();
        iicStop();
    }

    public void writeData(char data) {
        iicStart();
        write((char) 0x78);
        waitAck();
        write((char) 0x40);
        waitAck();
        write(data);
        waitAck();
        iicStop();
    }

    public void init() {
        for (char cmd : INIT_CMD_LIST) {
            writeCommand(cmd);
        }
    }

    public void setPosition(char x, char y) {
        writeCommand((char) (0xB0 + y));
        writeCommand((char) ((x & 0xf0 >> 4) | 0x10));
        writeCommand((char) (x & 0x0f));
    }

    public void displayOn() {
        writeCommand((char) 0x8D);
        writeCommand((char) 0x14);
        writeCommand((char) 0xAF);
    }

    public void displayOff() {
        writeCommand((char) 0x8D);
        writeCommand((char) 0x10);
        writeCommand((char) 0xAE);
    }

    public void clearLine(char line) {
        setPosition((char) 0, line);
        for (char x = 0; x < MAX_WIDTH; x++) {
            writeData((char) 0);
        }
    }

    public void fullLine(char line) {
        setPosition((char) 0, line);
        for (int x = 0; x < MAX_WIDTH; x++) {
            writeData((char) 0xFF);
        }
    }

    public void full() {
        for (char i = 0; i < MAX_LINE; i++) {
            fullLine(i);
        }
    }

    public void clear() {
        for (char i = 0; i < ONE_BYTE; i++) {
            clearLine(i);
        }
    }
}

